// Copyright (c) 2025, 大连理工大学 (Dalian University of Technology)
//
// Licensed under the Mulan PSL v2.
// You can use this file according to the terms and conditions of the Mulan PSL v2.
// You may obtain a copy of the License at
//
//     http://license.coscl.org.cn/MulanPSL2
//
// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
// EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. SEE THE MULAN PSL v2
// FOR MORE DETAILS.

#include "Import/BDFImport/BulkData/Element/CQUAD4Parser.h"

#include <algorithm>
#include <cstdint>
#include <iostream>

#include "Utility/Logging/SGLogger.h"

#include "DataStructure/Input/Element/CQUAD4Data.h"

#include "DBManager/DBServiceFactory.h"
#include "DBManager/IService/Input/Element/IElementService.h"

#include "Import/BDFImport/BDFImport.h"
#include "Import/BDFImport/BDFParserBase.h"

BULKDATA_ENTRY_PARSER_REG (CQUAD4);

using namespace SG::DBManager;
using namespace SG::Import;
using namespace SG::DataStructure;
/*
// file://./../../Doc/MarkDown/BulkData/CQUAD4/CQUAD4.md>
*/
// 以下需要修改
enum CQUAD4key : std::uint8_t
{
    CQUAD4KEY_EID = 2,
    CQUAD4KEY_PID = 3,          // Property identification number of a PSHELL, PCOMP, PCOMPG or PLPLANE or
                                // PLCOMP entry. (Integer > 0; Default = EID)
    CQUAD4KEY_G1          = 4,  // Grid point identification numbers of connection points.(Integers > 0, all unique.)
    CQUAD4KEY_G2          = 5,
    CQUAD4KEY_G3          = 6,
    CQUAD4KEY_G4          = 7,
    CQUAD4KEY_THETAorMCID = 8,  // Material property orientation angle in degrees. THETA is ignored for hyperelastic
                                // elements. See  Figure 9-52 . See Remark  10. (Real; Default = 0.0)
                                //  Material coordinate system identification number. The x-axis of the material coordinate
                                //  system is determined by projecting the T1-axis of the MCID coordinate system onto the
                                //  surface of the shell element as follows:
                                //  CORD1R,   x -axis of MCID the coordinate is projected onto shell surface and the
                                //  CORD2R    material angle is measured from the G1-G2 line to the to the projected x-
                                //            axis
                                //  CORD1C,   r-axis of MCID the coordinate is projected onto shell surface through the
                                //  CORD2C    element center and the material angle is measured from the G1-G2 line
                                //  CORD1S,   to the to the projected r-axis
                                //  CORD2S
                                //  Use DIAG 38 to print the computed THETA values. MCID is ignored for hyperelastic
                                //  elements. For SOL 600, only CORD2R is allowed. See Remark  10. (Integer > 0; If
                                //  blank, then THETA = 0.0 is assumed.)

    CQUAD4KEY_ZOFFS = 9,        // Offset from the surface of grid points to the element reference plane. ZOFFS is
                                // ignored for hyperelastic elements. See Remark  6. (Real)
    CQUAD4KEY_TFLAG = 13,       // An integer flag, signifying the meaning of the Ti values. (Integer 0, 1, or blank)
    CQUAD4KEY_T1    = 14,       // Membrane thickness of element at grid points G1 through G4. If “TFLAG” is zero or
                                // blank, then Ti are actual user specified thicknesses. See Remark  4. for default. (Real
                                //> 0.0 or blank, not all zero.) If “TFLAG” is one, then the Ti are fractions relative to the
                                // T value of the PSHELL. (Real > 0.0 or blank, not all zero. Default = 1.0) Ti are ignored
                                // for hyperelastic elements.
    CQUAD4KEY_T2 = 15,
    CQUAD4KEY_T3 = 16,
    CQUAD4KEY_T4 = 17,
};
SG::DataStructure::Common::Status BDF::BULKDATA::ParseCQUAD4 (const std::shared_ptr<SG::DBManager::DBServiceFactory>& dbServiceFactory,
                                                              std::vector<std::string>&                               dividedEntryInfo)
{
    SG::DataStructure::FEM::CQUAD4Data tempCQUAD4;

    // TODO(bug 001) m_dominId的正确填写
    tempCQUAD4.m_domainId = 1;

    int curIDKey = 1;  // 当前字符串是第几项

    for (auto curStrKey : dividedEntryInfo)
    {
        bool const isEmpty = is_all_space (curStrKey);
        if (isEmpty)
        {
            curIDKey++;
            continue;
        }

        bool const isFloat = BDF::covertToScientificNotation (curStrKey);

        switch (curIDKey)
        {
        case CQUAD4KEY_EID:
            tempCQUAD4.m_id  = convertToI64 (curStrKey);
            tempCQUAD4.m_pId = tempCQUAD4.m_id;
            break;
        case CQUAD4KEY_PID:
            tempCQUAD4.m_pId = convertToI64 (curStrKey);
            break;
        case CQUAD4KEY_G1:
            tempCQUAD4.m_g[0] = convertToI64 (curStrKey);
            break;
        case CQUAD4KEY_G2:
            tempCQUAD4.m_g[1] = convertToI64 (curStrKey);
            break;
        case CQUAD4KEY_G3:
            tempCQUAD4.m_g[2] = convertToI64 (curStrKey);
            break;
        case CQUAD4KEY_G4:
            tempCQUAD4.m_g[3] = convertToI64 (curStrKey);
            break;
        case CQUAD4KEY_THETAorMCID:
            if (!isFloat)
            {
                tempCQUAD4.m_mcId = convertToI64 (curStrKey);
            }
            else
            {
                tempCQUAD4.m_theta = convertToReal (curStrKey);
            }
            break;
        case CQUAD4KEY_ZOFFS:
            tempCQUAD4.m_zoffs = convertToReal (curStrKey);
            break;
        case CQUAD4KEY_T1:

            tempCQUAD4.m_ti[0] = convertToReal (curStrKey);
            break;
        case CQUAD4KEY_T2:
            tempCQUAD4.m_ti[1] = convertToReal (curStrKey);
            break;
        case CQUAD4KEY_T3:
            tempCQUAD4.m_ti[2] = convertToReal (curStrKey);
            break;
        case CQUAD4KEY_T4:
            tempCQUAD4.m_ti[3] = convertToReal (curStrKey);
            break;
        case CQUAD4KEY_TFLAG:
            tempCQUAD4.m_tflag = convertToI64 (curStrKey);
            if (1 == tempCQUAD4.m_tflag)
            {
                tempCQUAD4.m_ti[0] = tempCQUAD4.m_ti[1] = tempCQUAD4.m_ti[2] = tempCQUAD4.m_ti[3] = 1;
            }
            break;
        default:
            break;
        }
        curIDKey++;
    }

    return dbServiceFactory->get<IElementService> ()->Add (tempCQUAD4);
}
